package com.util;

import net.sf.json.JSONObject;
import org.apache.http.*;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

import java.io.*;
import java.net.*;
import java.nio.charset.Charset;
import java.util.*;

public class HttpClientUtil {
    private final static HttpClientBuilder httpClientBuilder = HttpClients.custom();
    static {
        //https 协议工厂
        SSLConnectionSocketFactory sslFactory = new SSLConnectionSocketFactory(SSLContexts.createSystemDefault(),
                new String[]{"TLSv1.2"},
                null,
                SSLConnectionSocketFactory.getDefaultHostnameVerifier());
        //创建注册对象
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https",sslFactory)
                .build();
        //创建连接池
        //创建 ConnectionManager 接口 new (连接池)
        PoolingHttpClientConnectionManager pool = new PoolingHttpClientConnectionManager(registry);
        //设置连接池最大连接数
        pool.setMaxTotal(5);
        //设置每个路由默认多少链接
        pool.setDefaultMaxPerRoute(5);
        //设置连接池属性
        httpClientBuilder.setConnectionManager(pool);

        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(1000 * 90) // 创建链接 （TCP协议的三次握手）超时时间
                .setSocketTimeout(1000 * 90) // 响应 获取响应内容 超时时间
                .setConnectionRequestTimeout(1000 * 30) // 从链接池 获取链接的超时时间
                .build();

        httpClientBuilder.setDefaultRequestConfig(requestConfig);

        //设置默认的请求头
        List<Header> headerList = new ArrayList<>();
        BasicHeader header = new BasicHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36 Edg/92.0.902.78");
        headerList.add(header);
        httpClientBuilder.setDefaultHeaders(headerList);

        //设置连接池为共享的
        httpClientBuilder.setConnectionManagerShared(true);

    }


    //post请求带连接管理的
    public static String doPostHasConnectionManager (String url, String body, Map<String,String> header) throws UnsupportedEncodingException {
        CloseableHttpClient httpClient = httpClientBuilder.build();
        HttpPost httpPost = new HttpPost(url);
        //设置json方式请求
        httpPost.addHeader("Content-Type","application/json;charset=UTF-8");
        //设置请求头
        if (header != null && header.size() > 0) {
            Iterator<Map.Entry<String, String>> iterator = header.entrySet().iterator();
            while(iterator.hasNext()){
                Map.Entry<String, String> next = iterator.next();
                httpPost.addHeader(next.getKey(),next.getValue());
            }
        }

        StringEntity jsonEntity = new StringEntity(body);
        jsonEntity.setContentType("application/json;charset=UTF-8");
        jsonEntity.setContentEncoding(Consts.UTF_8.name());
        httpPost.setEntity(jsonEntity);

        CloseableHttpResponse response = null;
        try{
            try{
                InputStreamReader input = new InputStreamReader(httpPost.getEntity().getContent());
                BufferedReader bf = new BufferedReader(input);
                String line = null;
                StringBuilder sb = new StringBuilder();
                while((line=bf.readLine()) != null){
                    sb.append(line);
                }
                System.out.println("发送的数据为" + sb.toString());
                System.out.println("请求的接口为" + url);
            }catch(Exception e){
                e.printStackTrace();
            }

            response = httpClient.execute(httpPost);
            String resStr = EntityUtils.toString(response.getEntity());;
            System.out.println("响应的数据为" + resStr);
            return resStr;
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            HttpClientUtils.closeQuietly(httpClient);
        }
        return null;
    }

    private HttpClientUtil() {
    }

    public static String doGet(String url, Map<String, String> param) {

        // 创建Httpclient对象
        CloseableHttpClient httpclient = HttpClients.createDefault();

        String resultString = "";
        CloseableHttpResponse response = null;
        try {
            // 创建uri
            URIBuilder builder = new URIBuilder(url);
            if (param != null) {
                for (String key : param.keySet()) {
                    builder.addParameter(key, param.get(key));
                }
            }
            URI uri = builder.build();

            // 创建http GET请求 链接超时，请求超时
            HttpGet httpGet = new HttpGet(uri);
//            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(60000).setConnectionRequestTimeout(60000).setSocketTimeout(60000).build();
//            httpGet.setConfig(requestConfig);

            // 执行请求
            response = httpclient.execute(httpGet);
            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
            }else {
                //错误日志保存
                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                httpclient.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return resultString;
    }

    //get请求
    public static String testGet(String url, Map<String, String> param) {
        //创建 CloseableHttpClient
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String result = null;
        try {
            URIBuilder uri = new URIBuilder(url);
            //get请求带参数
            List<NameValuePair> list = new LinkedList<>();

            NameValuePair[] aa=param.entrySet().stream().map(entry -> new BasicNameValuePair(entry.getKey(), entry.getValue())).toArray(BasicNameValuePair[]::new);
            List<NameValuePair> list11 = new LinkedList<>(Arrays.asList(aa));
            /*list.add(param1);
            list.add(param2);*/
            uri.setParameters(list11);
            HttpGet httpGet = new HttpGet(uri.build());
            //设置请求状态参数
            RequestConfig requestConfig = RequestConfig.custom()
                    .setConnectionRequestTimeout(30000)
                    .setSocketTimeout(30000)
                    .setConnectTimeout(30000).build();
            httpGet.setConfig(requestConfig);
            response = httpClient.execute(httpGet);
            int status = response.getStatusLine().getStatusCode();//获取返回状态值
            if (status == HttpStatus.SC_OK) {//请求成功
                HttpEntity httpEntity = response.getEntity();
                if(httpEntity != null){
                    result = EntityUtils.toString(httpEntity, "UTF-8");
                    EntityUtils.consume(httpEntity);//关闭资源
                    httpClient.close();
                    /*JSONObject jsonResult = JSONObject.fromObject(result);
                    // JSONObject如下格式
                    JSONArray jsonArray = jsonResult.getJSONArray("data");
                    for (int i = 0; i < jsonArray.size(); i++) {//只取一个值返回
                        result = jsonArray.getJSONObject(i).getString("对应key");
                    }*/
                    return result;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(response != null){
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(httpClient != null){
                try {
                    httpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    public static String doGet(String url) {
        return doGet(url, null);
    }

    public static String doPost(String url, Map<String, Object> param) {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            // 创建参数列表
            if (param != null) {
                List<NameValuePair> paramList = new ArrayList<>();
                for (String key : param.keySet()) {
                    paramList.add(new BasicNameValuePair(key, (String) param.get(key)));
                }
                // 模拟表单
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
                httpPost.setEntity(entity);
            }
            // 执行http请求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return resultString;
    }

    public static String doPost(String url) {
        return doPost(url, null);
    }


    /**
     * 向指定 URL 发送POST方法的请求
     *
     * @param url
     *            发送请求的 URL
     * @param param
     *            请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String sendPost(String url, String param) {
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        try {
            CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            conn.setRequestProperty("Content-type", "application/json; charset=utf-8");
            conn.setRequestProperty("Accept", "application/json");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setConnectTimeout(10*1000);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            // 发送请求参数
            out.print(param);
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(
                    new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            System.out.println("发送 POST 请求出现异常！"+e);
            e.printStackTrace();
        }
        //使用finally块来关闭输出流、输入流
        finally{
            try{
                if(out!=null){
                    out.close();
                }
                if(in!=null){
                    in.close();
                }
            }
            catch(IOException ex){
                ex.printStackTrace();
            }
        }
        return result;
    }

    public static String fetchDataPost(String url, Map<String, String> param) {
        String result = "";
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(600000).setConnectionRequestTimeout(600000)
                .setSocketTimeout(600000).build();
        httpPost.setConfig(requestConfig);
        httpPost.addHeader("Content-type", "application/json; charset=utf-8");
        httpPost.setHeader("Accept", "application/json");
        // 传入的header参数
        JSONObject k=new JSONObject();
        if (null != param) {
            for (Map.Entry entry : param.entrySet()) {
                k.put(entry.getKey(), entry.getValue());
            }
        }
        httpPost.setEntity(new StringEntity(k.toString(), Charset.forName("UTF-8")));
        try{
            InputStreamReader input = new InputStreamReader(httpPost.getEntity().getContent());
            BufferedReader bf = new BufferedReader(input);
            String line = null;
            StringBuilder sb = new StringBuilder();
            while((line=bf.readLine()) != null){
                sb.append(line);
            }
            System.out.println("发送的内容为"+sb.toString());
        }catch(Exception e){
            e.printStackTrace();
        }

        try {
            CloseableHttpResponse res = httpClient.execute(httpPost);
            result = EntityUtils.toString(res.getEntity());

            res.close();
        } catch (IOException e) {
            String errorMsg = url + ":httpPostWithJSON connect faild";
        } finally {
            try {
                httpClient.close();
            } catch (IOException e) {
                String errorMsg = url + ":close  httpClient faild";
            }
           return result;
        }
    }
}
